package pluginMain;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.scheduler.BukkitScheduler;

import com.comphenix.protocol.utility.StreamSerializer;

public class RGiftGroup extends JavaPlugin implements Listener {
	public static final String ColdDownFlag = ".ColdDown";
	public static final String LastRefreshTimeFlag = ".LastRefreshTime";
	public static final String InventoryFlag = "inv_";
	public static final String ItemStackFlag = ".ItemStack";
	public static final String PlayerTakeTimeFlag = ".PlayerTakeTime.";
	public static final String PlayerPermFlag = "RGiftGroup.gift.";
	public static final String TimeFormatFlag = "yyyyMMddHHmmssSSS";
	// public static boolean DebugFlag;
	public static Plugin plugin;
	public static BukkitScheduler scheduler;
	public static List<String> GroupList = new ArrayList<String>();
	public static HashMap<Integer, String> scheduleList = new HashMap<Integer, String>();
	public static HashMap<String, Integer> scheduleList_T = new HashMap<String, Integer>();
	public final Server lServer = getServer();
	public final String PLUGIN_NAME = "RemiliaNetwork Group Gift";
	public final Logger CONSOLE_LOGGER = this.getLogger();

	public static Long GetTime() {
		return Long.parseLong((new SimpleDateFormat(TimeFormatFlag))
				.format((new Date(System.currentTimeMillis()))));
	}

	public static int addGroupToTask(String group, int coldDown) {
		Runnable r = new refreshGroupTime(group);
		plugin.getLogger().info(
				"Thread for group: " + group + " will reexecute in " + coldDown
						* 20 + " tick(s)");
		return scheduler
				.scheduleSyncRepeatingTask(plugin, r, 0L, coldDown * 20);
	}

	public void LOGCONSOLE(String msg) {
		CONSOLE_LOGGER.info(msg);
	}

	@Override
	public void onEnable() {
		this.saveDefaultConfig();
		plugin = this;
		getServer().getPluginManager().registerEvents(this, this);
		scheduler = plugin.getServer().getScheduler();
		for (String g : getConfig().getKeys(false)) {
			GroupList.add(g);
			int taskId = addGroupToTask(g, getConfig().getInt(g + ColdDownFlag));
			scheduleList.put(taskId, g);
			scheduleList_T.put(g, taskId);
			LOGCONSOLE("TaskID:" + taskId
					+ " was bind to Schedule task group: " + g);
		}
		LOGCONSOLE(PLUGIN_NAME + " has been started.");
	}

	@Override
	public void onDisable() {
		this.saveConfig();
		getServer().getScheduler().cancelTasks(this);
		LOGCONSOLE(PLUGIN_NAME + " has been disabled.");
	}

	@Override
	public boolean onCommand(CommandSender sender, Command command,
			String label, String[] args) {
		switch (command.getName().toLowerCase()) {
		case "gift":
			if (sender instanceof Player) {
				Player p = (Player) sender;

				PlayerTakeThread t = new PlayerTakeThread(p);
				t.start();
			}
			return false;

		case "gadmin":
			if (args.length < 1)
				return false;
			switch (args[0]) {
			case "create":
				if (args.length != 3) {
					return showHelp(sender);
				} else {
					if (sender instanceof Player) {
						if (scheduleList.containsValue(args[1])) {
							sender.sendMessage(ChatColor.RED
									+ "Oppps ,This group(" + args[1]
									+ ") was already exist.");
						}
						Inventory invItems = RGiftGroup.this.getServer()
								.createInventory(null, 27,
										InventoryFlag + args[1]);
						CreateGroupThread t = new CreateGroupThread(args[1],
								Integer.parseInt(args[2]), sender, invItems);
						t.start();
						return true;
					} else {
						sender.sendMessage(ChatColor.RED
								+ "Can't create group in console");
						return true;
					}
				}
			case "edit":
				if (args.length < 2) {
					return showHelp(sender);
				} else {
					if (!scheduleList.containsValue(args[1])) {
						sender.sendMessage(ChatColor.RED + "Oppps ,This group("
								+ args[1] + ") is not exist.");
					}
					AlterGroupThread t;
					if (args.length == 3)
						t = new AlterGroupThread(args[1], sender,
								Integer.parseInt(args[2]));
					else if (args.length == 2) {
						if (!(sender instanceof Player)) {
							sender.sendMessage(ChatColor.RED
									+ "This command not support execute in console with only one argument");
							return true;
						}
						t = new AlterGroupThread(args[1], sender);
					} else
						return showHelp(sender);
					t.start();
				}
				return true;
			case "delete":
				if (args.length == 2) {
					if (!scheduleList.containsValue(args[1])) {
						sender.sendMessage(ChatColor.RED + "Oppps ,This group("
								+ args[1] + ") is not exist.");
					}

					scheduler.cancelTask(scheduleList_T.remove(scheduleList
							.remove(scheduleList_T.get(args[1]))));
					getConfig().set(args[1], null);
					RGiftGroup.plugin.saveConfig();
					sender.sendMessage(ChatColor.GREEN + "The group " + args[1]
							+ " was been delete successfuly.");
					return true;
				} else {
					sender.sendMessage(ChatColor.RED
							+ "You must specific a group to delete.");
					return true;
				}
			case "refresh":
				if (args.length == 2) {
					getConfig().set(args[1] + LastRefreshTimeFlag,
							RGiftGroup.GetTime());
				} else if (args.length == 3) {
					getConfig().set(args[1] + PlayerTakeTimeFlag + args[2], 0);
				} else
					return showHelp(sender);
				RGiftGroup.plugin.saveConfig();
				sender.sendMessage(ChatColor.GREEN + "Refresh successfully!");
			default:
				return showHelp(sender);
			}
		default:
			return showHelp(sender);
		}
	}

	public boolean showHelp(CommandSender sender) {
		sender.sendMessage(ChatColor.GREEN + PLUGIN_NAME);
		sender.sendMessage(ChatColor.GOLD + "/gift    " + ChatColor.GREEN
				+ " Take the gifts");
		if (sender.hasPermission("RGiftGroup.admin")) {
			sender.sendMessage(ChatColor.GOLD + "/gadmin    " + ChatColor.GREEN
					+ " Show Admin menu");
			sender.sendMessage(ChatColor.BOLD + "" + ChatColor.RED
					+ "-----------Sub commands----------");
			sender.sendMessage(ChatColor.RED + "(args) - Requir arg");
			sender.sendMessage(ChatColor.GREEN + "[args] - Opional arg");
			sender.sendMessage(ChatColor.GOLD + "create (Name) (Colddown)"
					+ ChatColor.GREEN + " Create a group");
			sender.sendMessage(ChatColor.GOLD + "edit (Name) [Colddown]"
					+ ChatColor.GREEN + " alter a group");
			sender.sendMessage(ChatColor.GOLD + "delete (Name) [Colddown]"
					+ ChatColor.GREEN + " delete a group");
			sender.sendMessage(ChatColor.GOLD + "refresh (Name) [PlayerName])"
					+ ChatColor.GREEN + " refresh a group or a player");
		}
		return true;
	}

	@EventHandler
	public void onInventoryClose(InventoryCloseEvent event) {
		HumanEntity player = event.getPlayer();
		Inventory inventory = event.getInventory();
		if (!player.hasPermission("RGiftGroup.admin")) {
			return;
		}
		if (inventory.getHolder() != null) {
			return;
		}
		if (inventory.getTitle().startsWith(InventoryFlag)) {
			InventoryCloseThread closeThread = new InventoryCloseThread(
					inventory);
			closeThread.start();
		}
	}

	static String createItemsData(Inventory inventory) {
		ItemStack[] itemStacks = inventory.getContents();
		StringBuilder stringBuilder = new StringBuilder();
		for (ItemStack itemStack : itemStacks) {
			if (itemStack != null) {
				try {
					stringBuilder.append(StreamSerializer.getDefault()
							.serializeItemStack(itemStack));
				} catch (IOException e) {
					e.printStackTrace();
				}
				stringBuilder.append(";");
			}
		}
		return stringBuilder.toString();

	}

	public static Inventory getInventory(String group, String flag) {
		Inventory inv = plugin.getServer().createInventory(null, 27,
				flag + group);
		String[] itemDatas = plugin.getConfig()
				.getString(group + ItemStackFlag).split(";");
		for (String string : itemDatas) {
			if (string.equals("")) {
				continue;
			}
			try {
				inv.addItem(StreamSerializer.getDefault().deserializeItemStack(
						string));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return inv;
	}
}

class CreateGroupThread extends Thread {
	String group;
	CommandSender player;
	Inventory inv;
	int cd;

	public CreateGroupThread(String group_, int coldDown_,
			CommandSender sender_, Inventory inv_) {
		player = sender_;
		inv = inv_;
		cd = coldDown_;
		group = group_;

	}

	@Override
	public void run() {
		if (!RGiftGroup.scheduleList.containsKey(group)) {
			RGiftGroup.plugin.getConfig().set(group + RGiftGroup.ColdDownFlag,
					cd);
			int taskId = RGiftGroup.addGroupToTask(group, cd);
			RGiftGroup.scheduleList.put(taskId, group);
			RGiftGroup.scheduleList_T.put(group, taskId);
			if (player instanceof Player)
				((Player) player).openInventory(inv);
			player.sendMessage(ChatColor.GREEN + "Create successfully!");
		} else {
			player.sendMessage(ChatColor.RED
					+ "This gorup is alread exist, also can try delete/refresh.");
		}
		RGiftGroup.plugin.saveConfig();
	}
}

class AlterGroupThread extends Thread {
	String group;
	CommandSender player;
	int cd;
	boolean changecd;

	public AlterGroupThread(String group_, CommandSender player_) {
		group = group_;
		player = player_;
		changecd = false;
	}

	public AlterGroupThread(String group_, CommandSender player_, int coldDown_) {
		group = group_;
		player = player_;
		cd = coldDown_;
		changecd = true;
	}

	@Override
	public void run() {
		if (changecd)
			RGiftGroup.plugin.getConfig().set(group + RGiftGroup.ColdDownFlag,
					cd);
		if (player instanceof Player)
			((Player) player).openInventory(RGiftGroup.getInventory(group,
					RGiftGroup.InventoryFlag));
		RGiftGroup.scheduler.cancelTask(RGiftGroup.scheduleList_T
				.remove(RGiftGroup.scheduleList
						.remove(RGiftGroup.scheduleList_T.get(group))));
		int taskId = RGiftGroup.addGroupToTask(group, cd);
		RGiftGroup.scheduleList.put(taskId, group);
		RGiftGroup.scheduleList_T.put(group, taskId);
		RGiftGroup.plugin.getLogger().info(
				group + " was been alter successfuly");
		RGiftGroup.plugin.saveConfig();
		player.sendMessage(ChatColor.GREEN + "Edit group successfully!");
	}
}

class PlayerTakeThread extends Thread {
	Player player;

	public PlayerTakeThread(Player player_) {
		player = player_;

	}

	@Override
	public void run() {
		boolean haveItem = false;
		Inventory inv = RGiftGroup.plugin.getServer().createInventory(null, 54,
				"Gifts");
		RGiftGroup.plugin.saveConfig();
		for (String g : RGiftGroup.GroupList) {
			if (player.hasPermission(RGiftGroup.PlayerPermFlag + g)) {
				long takedTime = RGiftGroup.plugin.getConfig().getLong(
						g + RGiftGroup.PlayerTakeTimeFlag + player.getName());
				long refreshTime = RGiftGroup.plugin.getConfig().getLong(
						g + RGiftGroup.LastRefreshTimeFlag);
				if (takedTime > refreshTime) {
					player.sendMessage(ChatColor.RED
							+ "You arleady take the gift: " + g);
					continue;
				} else {
					RGiftGroup.plugin.getConfig().set(
							g + RGiftGroup.PlayerTakeTimeFlag
									+ player.getName(), RGiftGroup.GetTime());
					RGiftGroup.plugin.saveConfig();
					ItemStack[] sItem = RGiftGroup.getInventory(g, "")
							.getContents();
					RGiftGroup.plugin.getLogger().info("" + sItem.length);
					haveItem = true;
					if (!sItem.equals(null))
						inv.addItem(sItem);
					continue;
				}
			}
		}
		if (haveItem)
			player.openInventory(inv);
	}
}

class InventoryCloseThread extends Thread {
	Inventory inv;

	public InventoryCloseThread(Inventory inv_) {
		inv = inv_;
	}

	@Override
	public void run() {
		String group = inv.getTitle().split("_")[1];
		RGiftGroup.plugin.getConfig().set(group + RGiftGroup.ItemStackFlag,
				RGiftGroup.createItemsData(inv));
		RGiftGroup.plugin.saveConfig();
	}
}

class refreshGroupTime implements Runnable {
	String group;

	public refreshGroupTime(String group_) {
		group = group_;
	}

	@Override
	public void run() {
		RGiftGroup.plugin.getLogger().info(
				group + " was been refreshed at " + RGiftGroup.GetTime());
		RGiftGroup.plugin.getConfig().set(
				group + RGiftGroup.LastRefreshTimeFlag, RGiftGroup.GetTime());
		RGiftGroup.plugin.saveConfig();
		for (Player p : RGiftGroup.plugin.getServer().getOnlinePlayers()) {
			if (p.hasPermission(RGiftGroup.PlayerPermFlag + group)) {
				p.sendMessage("Your gift " + group
						+ " was been refreshed , type /gift to take.");
			}
		}

	}
}